/* */

#include <map>
#include <set>

#include <QMap>

#include "pt_ext.h"

#include "mex.h"

using namespace std;

namespace pt_ext
{

char * lang(psa *trie) {
    unsigned int i, count=0, flag;
    ntrieNode *x;
    evnode *node;
    
    char *cvar, *cvar_dist;
    
    QMap<unsigned int, unsigned int> map;
    QMap<unsigned int, unsigned int> map2;
    
    // Allocate string
    cvar = (char *) malloc(sizeof(char)*1024);
    cvar_dist = (char *) malloc(sizeof(char)*1024);
    
    string s;
    string *sf = new string;
    
    int sf_size;
    char* sf_to_char;
    
    //s = str + "World";
    
    if (trie->parameters == NULL)
                return NULL;
            
    assert(trie->parameters != NULL);
            
    sprintf(cvar, "");
    for(i=0, count=0; i < trie->n; i++) {
        
        if (trie->nodeArray[i]->removed)
            continue;
        
        map.insert(count, i);
        map2.insert(trie->nodeArray[i]->nid, count);
        count++;
    }
    
    for(i=0; i < count; i++)
    {
        node = trie->nodeArray[map.value(i)];
        
        if (node->child->count < 1)
            continue;
        
        sprintf(cvar, "%s[] (state=%d) ->", cvar, i);
        s += cvar;
        sprintf(cvar, "");
        
        flag=1;
        NEDTRIE_FOREACH(x, ntrie_s, node->child) {
            
            if(!map2.contains(x->node->nid))
                mexErrMsgTxt("pt_ext.lang: map funtion does not contain x.\n");
                
            switch(trie->parameters[x->key-1].dist) {
            	case 0:
                    sprintf(cvar_dist ,"%f", trie->parameters[x->key-1].dist_parameters[0]);
                    break;
                case 1:
                    sprintf(cvar_dist ,"Wei(%f,%f)", trie->parameters[x->key-1].dist_parameters[0], trie->parameters[x->key-1].dist_parameters[1]);
                    break;
                case 2:
                    sprintf(cvar_dist ,"Logn(%f,%f)", trie->parameters[x->key-1].dist_parameters[0], trie->parameters[x->key-1].dist_parameters[1]);
                    break;
            }
            
            if (flag) {
                sprintf(cvar, "%s %s : (state'=%d)", cvar, cvar_dist, map2.value(x->node->nid));
                flag = 0;
            }
            else
                sprintf(cvar, "%s + %s : (state'=%d)", cvar, cvar_dist, map2.value(x->node->nid));
            
            s += cvar;
            sprintf(cvar, "");
        }
        s += ";\n";
    }
    
    sprintf(cvar, "module dyn\nstate: [0..%d];\n", count-1, cvar);
    *sf += cvar;
    *sf += s;
    *sf += "endmodule\n";
    
    sf_size = sf->size();
    //sf_to_char = malloc(sizeof(char)*sf_size);
    
    sf_to_char = (char*)malloc(sizeof(char)*sf->size()+1);
    sf_to_char[sf->size()] = '\0';
    memcpy(sf_to_char, sf->c_str(), sf->size());
    
    //sf_to_char = (char*)sf->c_str();
    
    return sf_to_char;
}

void matlab_gsmp_structure(psa *trie, double time, mxArray *plhs[], int *nlhs) {
    
    unsigned int i, n, n_state, n_event, e, n2;
    ntrieNode *x;
    int dims[]={1, 1};
    mwSize dims2[]={1,1,1};
    
    double *states, *events, *active_events, *p, *tim;
    
    // Create an event set
    set<unsigned int> event;
    
    map<unsigned int, int> map;
    
    n_state = 0;
    
    // Find the diferent events
    for(i=0; i<trie->n; i++) {
        if (trie->nodeArray[i]->removed == 0) {
            NEDTRIE_FOREACH(x, ntrie_s, trie->nodeArray[i]->child) {
                event.insert((unsigned int)x->key);
            }
            n_state++;
        }
    }
    
    n_event = (unsigned int) event.size();
    
    // A state set
    plhs[0] =  mxCreateDoubleMatrix(1, n_state, mxCOMPLEX);
    
    // A event set
    plhs[1] =  mxCreateDoubleMatrix(1, n_event, mxCOMPLEX);
    
    // A boolean active event matrix M(e,s)
    plhs[2] =  mxCreateDoubleMatrix(n_event, n_state, mxCOMPLEX);
    
    // A P matrix p(s',s,e)
    //plhs[3] =  mxCreateDoubleMatrix(n_state, n_state*n_event, mxCOMPLEX);
    dims2[0] = dims2[1] = n_state;
    dims2[2] = n_event;
    plhs[3] = mxCreateNumericArray(3, dims2, mxDOUBLE_CLASS, mxREAL);
    
    // A distribution cell array G(e)
    dims[0] = n_event;
    plhs[4] = mxCreateCellArray (1, dims);
    
    // time
    plhs[5] = mxCreateDoubleMatrix(1, 1, mxCOMPLEX);
    
    *nlhs = 6;
    
    states = (double *) mxGetData(plhs[0]);
    events = (double *) mxGetData(plhs[1]);
    active_events = (double *) mxGetData(plhs[2]);
    p = (double *) mxGetData(plhs[3]);
    tim = (double *) mxGetData(plhs[5]);
    *tim = time;
    
    
    // Set states
    for(i=0; i<n_state; i++) {
        states[i]=(double)i+1;
    }
    
    // Set events
    for(i=0; i<n_event; i++) {
        events[i]=(double)i+1;
    }
    
    // Set active events
    /*for(n=0; n<trie->n; n++) {
        if (trie->nodeArray[n]->removed == 0) {
            NEDTRIE_FOREACH(x, ntrie_s, trie->nodeArray[n]->child) {
                //mexPrintf("%d %d\n",x->key, (x->key)+(n)*n_state);
                active_events[Matrix2d(x->key, n+1, n_event)]=1;
            }
        }
    }*/
    
    // Set probability matrix
    /*n=0;
    for (i=0; i<n_state; i++) {
        if (trie->nodeArray[i]->removed == 0) {
            NEDTRIE_FOREACH(x, ntrie_s, trie->nodeArray[i]->child) {
                e = x->key;
                n++;
                n2 = x->node->nid;
                p[Matrix3d(n2,n,e)]=1;
            }
        }
    }*/
    
    // Set probabilistic distributions
    /*for (i=0; i<n_state; i++) {
        if (trie->nodeArray[i]->removed == 0) {
            NEDTRIE_FOREACH(x, ntrie_s, trie->nodeArray[i]->child) {
                map[i]=10;
                switch(x->dist) {
                    case 0:
                        //sprintf(cvar_dist ,"%f", x->dist_parameters[0]);
                        
                        break;
                    case 1:
                        //sprintf(cvar_dist ,"Wei(%f,%f)", x->dist_parameters[0], x->dist_parameters[1]);
                        
                        break;
                }
            }
        }
    }*/
    
}

}

